package com.t.bricks.bussiness.service.filecabinet.impl;

import java.io.File;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.t.bricks.bussiness.db.dao.filecabinet.FileCabinetDao;
import com.t.bricks.bussiness.db.entity.filecabinet.FileCabinet;
import com.t.bricks.bussiness.service.filecabinet.FileCabinetService;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.utils.function.data.SequenceUtil;
import com.t.bricks.utils.function.data.ValidDataUtil;
import com.t.bricks.utils.function.date.TimeUtil;
import com.t.bricks.utils.function.encode.MD5Util;
import com.t.bricks.utils.function.file.FileUtil;

@Service
public class FileCabinetServiceImpl implements FileCabinetService {
	
	@Autowired
	private FileCabinetDao fileCabinetDao;

	/**
	 * 文件上传及保存的根路径
	 */
	@Value("${UpFilePath:${user.dir}/temp/file/cabinet}")
	private String filePath;

	/**
	 * 加密串
	 */
	@Value("${encryption}")
	private String encryptionStr;

	/**
	 * 干扰串
	 */
	@Value("${disturb}")
	private String disturbStr;
	
	/**
	 * 数据验证
	 * @param operator
	 * @param project
	 * @return
	 */
	private MsgEmity validBaseData(String operator, String project) {
		if (null == operator || "".equals(operator.trim())) {
			return new MsgEmity(false, "操作人不能为空！");
		}
		
		if (null == project || "".equals(project.trim())) {
			return new MsgEmity(false, "“项目名称”不能为空！");
		}
		
		return new MsgEmity(true, "通过！");
	}
	
	/**
	 * 添加
	 * @param operator
	 * @param project
	 * @param fileName
	 * @param sPath
	 * @param sType
	 * @param sMD5
	 * @return
	 */
	@Override
	public MsgEmity add(String operator, String project, String fileName,
			String sPath, String sType, String sMD5) {
		//-- 数据验证 --//
		MsgEmity me = this.validBaseData(operator, project);
		if (!me.isSuccess()) {
			return me;
		}
		
		//-- 查询是否存在相同记录 --//
		me = fileCabinetDao.findSameDataCount(fileName, project, sMD5);
		Integer count = me.getData();
		if (count.intValue() == 7009) {//7007没发现重复,7008查询异常,7009发现重复
			return new MsgEmity(true, "文件上传成功！", sMD5);
		}
		
		if (count.intValue() == 7008) {//7007没发现重复,7008查询异常,7009发现重复
			return new MsgEmity(false, "查询失败，请稍后重试！");
		}
		
		//-- 构造数据 --//
		FileCabinet fileCabinet = new FileCabinet();
		Date date = new Date();
		
		String vNewId = SequenceUtil.getSequence(20);// 取流水号
		
		fileCabinet.setsId(vNewId);
		fileCabinet.setsProgram(project);
		fileCabinet.setsName(fileName);
		fileCabinet.setsPath(sPath.replaceAll("\\\\", "/").replaceAll("//", "/"));
		fileCabinet.setsFileMd5(sMD5);
		fileCabinet.setiCount(1);
		fileCabinet.setsCreator(operator);
		fileCabinet.setdCreateDate(date);
		fileCabinet.setsModifieder(operator);
		fileCabinet.setdModifiedDate(date);
		fileCabinet.setiState(1);
		fileCabinet.setiIndex(1);
		fileCabinet.setiVersion(1);
		
		//-- 类型转换 --//
		Integer iType = changesType(sType);
		fileCabinet.setiType(iType);
		
		//-- 对记录进行加密 --//
		String dataMD5 = createMd5(fileCabinet);
		fileCabinet.setsRecordKey(dataMD5);
		
		//-- 保存数据 --//
		me = fileCabinetDao.add(fileCabinet);
		if (!me.isSuccess()) {
			return me;
		}
		
		return new MsgEmity(me.isSuccess(), me.getMsg(), vNewId);
	}
	
	/**
	 * 修改
	 * @param sId
	 * @param sModifieder
	 * @return
	 */
	@Override
	public MsgEmity edit(String sId, String sModifieder) {
		if (null == sId || "".equals(sId)) {
			return new MsgEmity(false, "记录编号不能为空！", 8301);
		}
		
		if (null == sModifieder || "".equals(sModifieder.trim())) {
			return new MsgEmity(false, "操作人不能为空！", 8302);
		}
		
		MsgEmity me = fileCabinetDao.findById(sId);
		if (!me.isSuccess()) {
			return me;
		}
		
		FileCabinet fileCabinet = me.getData();
		
		//-- 验证数据是否被篡改 --//
		String sMD5 = createMd5(fileCabinet);
		if (!sMD5.equals(fileCabinet.getsRecordKey()) && sMD5 != fileCabinet.getsRecordKey()) {
			return new MsgEmity(false, "记录已被篡改！", 8303);
		}
		
		//-- 构造数据 --//
		fileCabinet.setiCount(fileCabinet.getiCount() +1);
		fileCabinet.setiVersion(fileCabinet.getiVersion() +1);
		fileCabinet.setsModifieder(sModifieder);
		fileCabinet.setdModifiedDate(new Date());
		
		sMD5 = createMd5(fileCabinet);
		fileCabinet.setsRecordKey(sMD5);
		
		me = fileCabinetDao.edit(fileCabinet);
		if (!me.isSuccess()) {
			return me;
		}
		
		return new MsgEmity(true, me.getMsg(), sId);
	}
	
	/**
	 * 根据项目名、文件名、文件key查询数据
	 * @param sProgram 
	 * @param fileName
	 * @param sFileMd5
	 * @return
	 */
	@Override
	public MsgEmity findByNameAndKey(String sProgram, String fileName, String sFileMd5) {
		if (null == sProgram || "".equals(sProgram)) {
			return new MsgEmity(false, "项目名不能为空！", 8101);
		}
		
		if (null == sFileMd5 || "".equals(sFileMd5)) {
			return new MsgEmity(false, "文件名不能为空！", 8102);
		}
		
		if (null == sFileMd5 || "".equals(sFileMd5.trim())) {
			return new MsgEmity(false, "文件key不能为空！", 8103);
		}
		
		return fileCabinetDao.findByNameAndKey(sProgram, fileName, sFileMd5);
	}
	
	/**
	 * 判断是新增还是修改
	 * @param sId
	 * @param operator
	 * @param project
	 * @param fileName
	 * @param sPath
	 * @param sType
	 * @param sMD5
	 * @return
	 */
	@Override
	public MsgEmity operateData(String operator, String project,
			String fileName, String sPath, String sType, String sMD5) {
		//-- 判断是否已存在相同记录 --//
		MsgEmity me = fileCabinetDao.findByNameAndKey(project, fileName, sMD5);
		if (!me.isSuccess()) {
			return me;
		}
		
		if (null == me.getData()) {
			me = add(operator, project, fileName, sPath, sType, sMD5);
		} else {
			FileCabinet fileCabinet = me.getData();
			me = edit(fileCabinet.getsId(), operator);
		}
		
		return me;
	}
	
	/**
	 * 根据编号查询数据
	 * @Param sId
	 * @return
	 */
	@Override
	public MsgEmity findById(String sId) {
		if (null == sId || "".equals(sId)) {
			return new MsgEmity(false, "记录编号不能为空！", 8001);
		}
		
		return fileCabinetDao.findById(sId);
	}
	
	/**
	 * 创建MD5值
	 * @param fileCabinet
	 * @return
	 */
	private String createMd5(FileCabinet fileCabinet) {
		StringBuilder str = new StringBuilder();
		
		str.append(fileCabinet.getsId());
		str.append(";");
		str.append(fileCabinet.getsPath());
		str.append(";");
		str.append(fileCabinet.getsName());
		str.append(";");
		str.append(fileCabinet.getsProgram());
		str.append(";");
		str.append(fileCabinet.getiType());
		str.append(";");
		str.append(fileCabinet.getsFileMd5());
		str.append(";");
		str.append(fileCabinet.getsMemo());
		str.append(";");
		str.append(fileCabinet.getsCreator());
		str.append(";");
		str.append(TimeUtil.toStr(fileCabinet.getdCreateDate(), "yyyy-MM-dd HH:mm:00"));
		str.append(";");
		str.append(fileCabinet.getsModifieder());
		str.append(";");
		str.append(TimeUtil.toStr(fileCabinet.getdModifiedDate(), "yyyy-MM-dd HH:mm:00"));
		str.append(";");
		str.append(fileCabinet.getiState());
		str.append(";");
		str.append(fileCabinet.getiIndex());
		str.append(";");
		str.append(fileCabinet.getiVersion());
		str.append(";");
		
		return MD5Util.md5(str.toString());
	}
	
	/**
	 * 转换类型
	 * @param sType
	 * @return
	 */
	private Integer changesType(String sType) {
		int iType = 0;
		if (sType.indexOf("jpg") != -1
				|| sType.indexOf("jpeg") != -1
				|| sType.indexOf("png") != -1
				|| sType.indexOf("bmp") != -1) {
			iType = 1;
		} else if (sType.indexOf("pdf") != -1) {
			iType = 2;
		}
		
		return iType;
	}

	/**
	 * 文件上传
	 * @param file 文件
	 * @param person 操作人
	 * @param project 项目名
	 * @param requestDate 请求时间
	 * @param checkKey 验证key
	 * @return
	 */
	@Override
	public MsgEmity upFile(MultipartFile file, String person, String project,
			String requestDate, String checkKey) {
		MsgEmity me = ValidDataUtil.checkQueryKey(checkKey, requestDate, disturbStr, person, project);
		if (!me.isSuccess()) {
			return me;
		}
		
		return this.upFile(file, person, project);
	}
	
	/**
	 * 文件上传
	 * @param file 文件
	 * @param person 操作人
	 * @param project 项目名
	 * @return
	 */
	@Override
	public MsgEmity upFile(MultipartFile file, String person, String project) {
		if (null == file || file.isEmpty()) {
			return new MsgEmity(false, "上传失败，文件不存在！", 8001);
		}
		
		String tmpStr = SequenceUtil.getSequence(20);// 取流水号
		
		//-- MultipartFile转file --//
		StringBuilder tempPath = new StringBuilder()
			.append(filePath)
			.append("/temp/")
			.append(tmpStr)
			.append(file.getOriginalFilename().substring(
					file.getOriginalFilename().lastIndexOf(".")));
		MsgEmity me = FileUtil.multipartFileToFile(file, tempPath.toString());
		if (!me.isSuccess()) {
			return me;
		}
		
		File tempFile = me.getData();
		
		//-- 获取文件MD5值 --//
		me = FileUtil.getFileMD5(tempFile);
		if (!me.isSuccess()) {
			return me;
		}
		
		String sMD5 = me.getData();

		//-- 构造文件保存路径 --//
		StringBuilder savePath = new StringBuilder()
				.append(filePath).append("/")
				.append(project).append("/")
				.append(sMD5)
				.append(file.getOriginalFilename().substring(
						file.getOriginalFilename().lastIndexOf(".")) );
		
		String sType = file.getContentType();// 获取文件类型
		String sName = file.getOriginalFilename().trim();// 获取文件名
		
		//-- 判断是否已存在相同文件 --//
		me = FileUtil.exist(savePath.toString());
		if (me.isSuccess()) {// 文件已存在
			tempFile.delete();// 删除临时文件
			
			//-- 判断是新增还是修改 --//
			me = this.operateData(person, project, sName, savePath.toString(), sType, sMD5);
			if (!me.isSuccess()) {
				return me;
			}
			
			return new MsgEmity(true, "文件上传成功！", me.getData());
		}
		
		//-- 保存文件到本地 --//
		me = FileUtil.copyFile(true, tempPath.toString(), savePath.toString());
		if (!me.isSuccess()) {
			tempFile.delete();// 删除临时文件
			return me;
		}
		
		me = this.add(person, project, sName, savePath.toString(), sType, sMD5);
		if (!me.isSuccess()) {
			tempFile.delete();// 删除临时文件
			return new MsgEmity(false, "添加记录失败！", 8005);
		}
		
		String dataKey = me.getData();// 获取记录编号
		
		tempFile.delete();// 删除临时文件,真实文件已经放到指定'project'文件夹下
		
		return new MsgEmity(true, "文件上传成功！", dataKey);
	}

	/**
	 * 文件上传(自定义保存路径)
	 * @param file 文件
	 * @param person 操作人
	 * @param project 项目名
	 * @param customPath 自定义路径
	 * @param requestDate 请求时间
	 * @param checkKey 验证key
	 * @return
	 */
	@Override
	public MsgEmity upFileCustom(MultipartFile file, String person,
			String project, String customPath, String requestDate, String checkKey) {
		MsgEmity me = ValidDataUtil.checkQueryKey(checkKey, requestDate, disturbStr, person, project, customPath);
		if (!me.isSuccess()) {
			return me;
		}
		
		if (null == file || file.isEmpty()) {
			return new MsgEmity(false, "上传失败，文件不存在！", 8001);
		}

		//-- MultipartFile转file --//
		StringBuilder tempPath = new StringBuilder()
					.append(filePath)
					.append("/temp/")
					.append(SequenceUtil.getSequence(20))// 取流水号
					.append(file.getOriginalFilename().substring(
							file.getOriginalFilename().lastIndexOf(".")));
		me = FileUtil.multipartFileToFile(file, tempPath.toString());
		if (!me.isSuccess()) {
			return me;
		}
		
		File tempFile = me.getData();
		
		//-- 获取文件MD5值 --//
		me = FileUtil.getFileMD5(tempFile);
		if (!me.isSuccess()) {
			return me;
		}
		
		String sMD5 = me.getData();
		
		//-- 构造文件保存路径 --//
		StringBuilder savePath = new StringBuilder()
			.append(filePath).append("/")
			.append(project).append("/")
			.append(customPath).append("/")
			.append(sMD5)
			.append(file.getOriginalFilename().substring(
						file.getOriginalFilename().lastIndexOf(".")));
		// 获取文件类型
		String sType = file.getContentType();
		// 获取文件名
		String sName = file.getOriginalFilename().trim();
		
		//-- 判断是否已存在相同文件 --//
		me = FileUtil.exist(savePath.toString());
		if (me.isSuccess()) {// 文件已存在
			tempFile.delete();// 删除临时文件
			
			//-- 判断是新增还是修改 --//
			me = this.operateData(person, project, sName, savePath.toString(), sType, sMD5);
			if (!me.isSuccess()) {
				return new MsgEmity(false, "保存记录失败！", 8003);
			}
			
			return new MsgEmity(true, "文件上传成功！", me.getData());
		}
		
		//-- 保存文件到本地 --//
		me = FileUtil.copyFile(true, tempPath.toString(), savePath.toString());
		if (!me.isSuccess()) {
			tempFile.delete();// 删除临时文件
			return me;
		}
		
		me = this.add(person, project, sName, savePath.toString(), sType, sMD5);
		if (!me.isSuccess()) {
			tempFile.delete();// 删除临时文件
			return new MsgEmity(false, "添加记录失败！", 8004);
		}
		
		String dataKey = me.getData();// 获取记录编号
		
		tempFile.delete();// 删除临时文件
		
		return new MsgEmity(true, "文件上传成功！", dataKey);
	}

	/**
	 * 验证请求密钥
	 * @param checkKey 请求密钥
	 * @param sDatas 请求值(数组)
	 * @return
	 */
	@Override
	public MsgEmity validateCheckKey(String checkKey, String...sDatas) {
		if (null == checkKey || "".equals(checkKey.trim())) {
			return MsgEmity.err(8101, "验证密钥不能为空");
		}
		
		if (null == sDatas || sDatas.length < 1) {
			return MsgEmity.err(8102, "请求数据为空，验证无效");
		}
		
		StringBuilder sb = new StringBuilder();
		for (String string : sDatas) {
			sb.append(string).append(";");
		}
		
		sb.append(disturbStr);//加入干扰串
		
		String result = MD5Util.MD5(sb.toString());
		if (!checkKey.trim().equals(result)) {
			return MsgEmity.err(8103, "请求密钥验证不通过");
		}
		
		return MsgEmity.success("请求密钥验证通过");
	}
	
	/**
	 * 判断文件是否存在
	 * @param sRecordId
	 * @return
	 */
	@Override
	public MsgEmity checkFileExist(String sId) {
		if (null == sId || "".equals(sId.trim())) {
			return new MsgEmity(false, "文件编号参数不能为空", 8001);
		}
		
		MsgEmity me = fileCabinetDao.findPathById(sId);
		if (!me.isSuccess()) {
			return me;
		}
		
		String sPath = me.getData();
		if (null == sPath || "".equals(sPath.trim())) {
			return new MsgEmity(false, "文件信息记录内缺失文件存储路径", 8002);
		}

		File file = new File(sPath.trim());
		if (!file.exists() || !file.isFile()) {
			return new MsgEmity(false, "文件信息记录内缺失文件存储路径在实际存储中不存在,请联系管理员是否进行了文件迁移", 8003);
		}
		
		return MsgEmity.success(8999, "找到文件,文件大小:", String.valueOf(file.length()), "字节");
	}
	
}
